home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Environments / PowerMacOberon feb96 / Source / CRA.Mod (.txt) < prev    next >
Encoding:
Oberon Text  |  1994-07-11  |  25.8 KB  |  814 lines  |  [.Ob./.Ob4]

  1. Syntax10.Scn.Fnt
  2. MODULE CRA;  (* handles the DFA *)
  3. IMPORT Oberon, Texts, Sets, CRS, CRT;
  4. CONST
  5.     maxStates = 300;
  6.     EOL = 0DX;
  7.     State = POINTER TO StateNode;
  8.     Action = POINTER TO ActionNode;
  9.     Target = POINTER TO TargetNode;
  10.     StateNode = RECORD         (*state of finite automaton*)
  11.         nr: INTEGER;  (*state number*)
  12.         firstAction: Action;   (*to first action of this state*)
  13.         endOf: INTEGER;  (*nr. of recognized token if state is final*)
  14.         ctx: BOOLEAN;  (*TRUE: state reached by contextTrans*)
  15.         next: State
  16.     END;
  17.     ActionNode = RECORD    (*action of finite automaton*)
  18.         typ: INTEGER;       (*type of action symbol: char, class*)
  19.         sym: INTEGER;       (*action symbol*)
  20.         tc: INTEGER;       (*transition code: normTrans, contextTrans*)
  21.         target: Target;        (*states after transition with input symbol*)
  22.         next: Action;
  23.     END;
  24.     TargetNode = RECORD    (*state after transition with input symbol*)
  25.         state:  State;       (*target state*)
  26.         next:   Target;
  27.     END;
  28.     Comment    = POINTER TO CommentNode;
  29.     CommentNode = RECORD   (* info about a comment syntax *)
  30.         start,stop: ARRAY 2 OF CHAR;
  31.         nested:     BOOLEAN;
  32.         next:       Comment;
  33.     END;
  34.     Melted     = POINTER TO MeltedNode;
  35.     MeltedNode = RECORD    (* info about melted states *)
  36.         set:   CRT.Set;      (* set of old states *)
  37.         state: State;      (* new state *)
  38.         next:  Melted;
  39.     END;
  40.     firstState: State;
  41.     lastState:    State;      (* last allocated state  *)
  42.     rootState:    State;      (* start state of DFA    *)
  43.     lastSimState: INTEGER;      (* last non melted state *)
  44.     stateNr: INTEGER;  (*number of last allocated state*)
  45.     firstMelted:  Melted;       (* list of melted states *)
  46.     firstComment: Comment;      (* list of comments      *)
  47.     out: Texts.Writer;  (* current output *)
  48.     fram: Texts.Reader;  (* scanner frame input *)
  49. PROCEDURE SemErr(nr: INTEGER);
  50. BEGIN CRS.Error(200+nr, CRS.pos)
  51. END SemErr;
  52. PROCEDURE Put(ch: CHAR);
  53. BEGIN Texts.Write(out, ch) END Put;
  54. PROCEDURE PutS(s: ARRAY OF CHAR);
  55.     VAR i: INTEGER;
  56. BEGIN i := 0;
  57.     WHILE (i < LEN(s)) & (s[i] # 0X) DO
  58.         IF s[i] = "$" THEN Texts.WriteLn(out) ELSE Texts.Write(out, s[i]) END;
  59.         INC(i)
  60. END PutS;
  61. PROCEDURE PutI(i: INTEGER);
  62. BEGIN Texts.WriteInt(out, i, 0) END PutI;
  63. PROCEDURE PutI2(i, n: INTEGER);
  64. BEGIN Texts.WriteInt(out, i, n) END PutI2;
  65. PROCEDURE PutC(ch: CHAR);
  66. BEGIN
  67.     IF (ch < " ") OR (ORD(ch) = 34) THEN PutS("CHR("); PutI(ORD(ch)); Put(")")
  68.     ELSE Put(CHR(34)); Put(ch); Put(CHR(34))
  69. END PutC;
  70. PROCEDURE PutRange(s: CRT.Set);
  71.     VAR lo, hi: ARRAY 32 OF CHAR; top, i: INTEGER; s1: CRT.Set;
  72. BEGIN
  73.     (*----- fill lo and hi *)
  74.     top := -1; i := 0;
  75.     WHILE i < 128 DO
  76.         IF Sets.In(s, i) THEN
  77.             INC(top); lo[top] := CHR(i); INC(i);
  78.             WHILE (i < 128) & Sets.In(s, i) DO INC(i) END;
  79.             hi[top] := CHR(i - 1)
  80.         ELSE INC(i)
  81.         END
  82.     END;
  83.     (*----- print ranges *)
  84.     IF (top = 1) & (lo[0] = 0X) & (hi[1] = 7FX) & (CHR(ORD(hi[0]) + 2) = lo[1]) THEN
  85.         Sets.Fill(s1); Sets.Differ(s1, s); PutS("~ ("); PutRange(s1); Put(")")
  86.     ELSE
  87.         i := 0;
  88.         WHILE i <= top DO
  89.             IF hi[i] = lo[i] THEN   PutS("(ch="); PutC(lo[i])
  90.             ELSIF lo[i] = 0X THEN   PutS("(ch<="); PutC(hi[i])
  91.             ELSIF hi[i] = 7FX THEN PutS("(ch>="); PutC(lo[i])
  92.             ELSE PutS("(ch>="); PutC(lo[i]); PutS(") & (ch<="); PutC(hi[i])
  93.             END;
  94.             Put(")");
  95.             IF i < top THEN PutS(" OR ") END;
  96.             INC(i)
  97.         END
  98. END PutRange;
  99. PROCEDURE PutChCond(ch: CHAR);
  100. BEGIN
  101.     PutS("(ch ="); PutC(ch); Put(")")
  102. END PutChCond;
  103. PROCEDURE Length*(s: ARRAY OF CHAR): INTEGER;
  104.     VAR i: INTEGER;
  105. BEGIN
  106.     i:=0; WHILE (i < LEN(s)) & (s[i] # 0X) DO INC(i) END;
  107.     RETURN i
  108. END Length;
  109. PROCEDURE AddAction(act:Action; VAR head:Action);
  110. VAR a,lasta: Action;
  111. BEGIN
  112.     a := head; lasta := NIL;
  113.     LOOP
  114.         IF (a = NIL)                (*collecting classes at the front gives better*)
  115.         OR (act^.typ < a^.typ) THEN (*performance*)
  116.             act^.next := a;
  117.             IF lasta = NIL THEN head := act ELSE lasta^.next := act END;
  118.             EXIT;
  119.         END;
  120.         lasta := a; a := a^.next;
  121.     END;
  122. END AddAction;
  123. PROCEDURE DetachAction(a:Action; VAR L:Action);
  124. BEGIN
  125.     IF L = a THEN L := a^.next ELSIF L # NIL THEN DetachAction(a, L^.next) END
  126. END DetachAction;
  127. PROCEDURE TheAction (state: State; ch: CHAR): Action;
  128.     VAR a: Action; set: CRT.Set;
  129. BEGIN
  130.     a := state.firstAction;
  131.     WHILE a # NIL DO
  132.         IF a.typ = CRT.char THEN
  133.             IF ORD(ch) = a.sym THEN RETURN a END
  134.         ELSIF a.typ = CRT.class THEN
  135.             CRT.GetClass(a^.sym, set);
  136.             IF Sets.In(set, ORD(ch)) THEN RETURN a END
  137.         END;
  138.         a := a.next
  139.     END;
  140.     RETURN NIL
  141. END TheAction;
  142. PROCEDURE AddTargetList(VAR lista, listb: Target);
  143. VAR p,t: Target;
  144.     PROCEDURE AddTarget(t: Target; VAR list:Target);
  145.     VAR p,lastp: Target;
  146.     BEGIN
  147.         p:=list; lastp:=NIL;
  148.         LOOP
  149.             IF (p = NIL) OR (t^.state.nr < p^.state.nr) THEN EXIT END;
  150.             IF p^.state = t^.state THEN RETURN END;
  151.             lastp := p; p := p^.next
  152.         END;
  153.         t^.next:=p;
  154.         IF lastp=NIL THEN list:=t ELSE lastp^.next:=t END
  155.     END AddTarget;
  156. BEGIN
  157.     p := lista;
  158.     WHILE p # NIL DO
  159.         NEW(t); t^.state:=p^.state; AddTarget(t, listb);
  160.         p := p^.next
  161. END AddTargetList;
  162. PROCEDURE NewMelted(set: CRT.Set; state: State): Melted;
  163. VAR melt: Melted;
  164. BEGIN
  165.     NEW(melt); melt^.set := set; melt^.state := state;
  166.     melt^.next := firstMelted; firstMelted := melt;
  167.     RETURN melt
  168. END NewMelted;
  169. PROCEDURE NewState(): State;
  170.     VAR state: State;
  171. BEGIN
  172.     NEW(state); INC(stateNr); state.nr := stateNr;
  173.     state.firstAction := NIL; state.endOf := CRT.noSym; state.ctx := FALSE; state.next := NIL;
  174.     IF firstState = NIL THEN firstState := state ELSE lastState.next := state END;
  175.     lastState := state;
  176.     RETURN state
  177. END NewState;
  178. PROCEDURE NewTransition(from, to: State; typ, sym, tc: INTEGER);
  179.     VAR a: Action; t: Target;
  180. BEGIN
  181.     IF to = firstState THEN SemErr(21) END;
  182.     NEW(t); t^.state := to; t^.next := NIL;
  183.     NEW(a); a^.typ := typ; a^.sym := sym; a^.tc := tc; a^.target := t;
  184.     AddAction(a, from.firstAction)
  185. END NewTransition;
  186. PROCEDURE NewComment*(from, to: INTEGER; nested: BOOLEAN);
  187.     VAR com: Comment;
  188.     PROCEDURE MakeStr(gp: INTEGER; VAR s: ARRAY OF CHAR);
  189.         VAR i, n: INTEGER; gn: CRT.GraphNode; set: CRT.Set;
  190.     BEGIN
  191.         i := 0;
  192.         WHILE gp # 0 DO
  193.             CRT.GetNode(gp, gn);
  194.             IF gn.typ = CRT.char THEN 
  195.                 IF i < 2 THEN s[i] := CHR(gn.p1) END; INC(i)
  196.             ELSIF gn.typ = CRT.class THEN
  197.                 CRT.GetClass(gn.p1, set);
  198.                 IF Sets.Elements(set, n) # 1 THEN SemErr(26) END;
  199.                 IF i < 2 THEN s[i] := CHR(n) END; INC(i)
  200.             ELSE SemErr(22) 
  201.             END;
  202.             gp := gn.next
  203.         END;
  204.         IF i > 2 THEN SemErr(25) ELSIF i < 2 THEN s[i] := 0X END
  205.     END MakeStr;
  206. BEGIN
  207.     NEW(com);
  208.     MakeStr(from, com^.start); MakeStr(to, com^.stop);
  209.     com^.nested := nested;
  210.     com^.next := firstComment; firstComment := com
  211. END NewComment;
  212. PROCEDURE MakeSet(p: Action; VAR set: CRT.Set);
  213. BEGIN
  214.     IF p^.typ = CRT.class THEN CRT.GetClass(p^.sym, set)
  215.     ELSE Sets.Clear(set); Sets.Incl(set, p^.sym)
  216. END MakeSet;
  217. PROCEDURE ChangeAction(a: Action; set: CRT.Set);
  218. VAR nr: INTEGER;
  219. BEGIN
  220.     IF Sets.Elements(set, nr) = 1 THEN a^.typ := CRT.char; a^.sym := nr
  221.     ELSE
  222.         nr := CRT.ClassWithSet(set);
  223.         IF nr < 0 THEN nr := CRT.NewClass("#0", set) END; (*class with dummy name*)
  224.         a^.typ := CRT.class; a^.sym := nr
  225. END ChangeAction;
  226. PROCEDURE CombineShifts;
  227.     VAR state: State; n: INTEGER; a, b, c: Action; seta, setb: CRT.Set;
  228. BEGIN
  229.     state := firstState;
  230.     WHILE state # NIL DO
  231.         a := state.firstAction;
  232.         WHILE a # NIL DO
  233.             b := a^.next;
  234.             WHILE b # NIL DO
  235.                 IF (a^.target^.state = b^.target^.state) & (a^.tc = b^.tc) THEN
  236.                     MakeSet(a, seta); MakeSet(b, setb); Sets.Unite(seta, setb);
  237.                     ChangeAction(a, seta);
  238.                     c := b; b := b^.next; DetachAction(c, a)
  239.                 ELSE b := b^.next
  240.                 END
  241.             END;
  242.             a := a^.next
  243.         END;
  244.         state := state.next
  245. END CombineShifts;
  246. PROCEDURE DeleteRedundantStates;
  247.     action: Action;
  248.     state, s1, s2: State;
  249.     used: CRT.Set;
  250.     newState: ARRAY maxStates OF State;
  251.     PROCEDURE FindUsedStates(state: State);
  252.     VAR action: Action;
  253.     BEGIN
  254.         IF Sets.In(used, state.nr) THEN RETURN END;
  255.         Sets.Incl(used, state.nr);
  256.         action := state.firstAction;
  257.         WHILE action # NIL DO
  258.             FindUsedStates(action^.target^.state);
  259.             action:=action^.next
  260.         END
  261.     END FindUsedStates;
  262.     PROCEDURE DelUnused;
  263.         VAR state: State;
  264.     BEGIN
  265.         state := firstState.next; lastState := firstState; stateNr := 0; (*firstState has number 0*)
  266.         WHILE state # NIL DO
  267.             IF Sets.In(used, state.nr) THEN INC(stateNr); state.nr := stateNr; lastState := state
  268.             ELSE lastState.next := state.next
  269.             END;
  270.             state := state.next
  271.         END
  272.     END DelUnused;
  273. BEGIN
  274.     Sets.Clear(used); FindUsedStates(firstState);
  275.     (*---------- combine equal final states ------------*)
  276.     s1 := firstState.next;  (*first state cannot be final*)
  277.     WHILE s1 # NIL DO
  278.         IF Sets.In(used, s1.nr) & (s1.endOf # CRT.noSym) &  (s1.firstAction = NIL) & ~ s1.ctx THEN
  279.             s2 := s1.next;
  280.             WHILE s2 # NIL DO
  281.                 IF Sets.In(used, s2.nr) & (s1.endOf = s2.endOf) & (s2.firstAction = NIL) & ~ s2.ctx THEN
  282.                     Sets.Excl(used, s2.nr); newState[s2.nr] := s1
  283.                 END;
  284.                 s2 := s2.next
  285.             END
  286.         END;
  287.         s1 := s1.next
  288.     END;
  289.     state := firstState;    (*> state := firstState.next*)
  290.     WHILE state # NIL DO
  291.         IF Sets.In(used, state.nr) THEN
  292.             action := state.firstAction;
  293.             WHILE action # NIL DO
  294.                 IF ~ Sets.In(used, action.target.state.nr) THEN
  295.                     action^.target^.state := newState[action.target.state.nr]
  296.                 END;
  297.                 action := action^.next
  298.             END
  299.         END;
  300.         state := state.next
  301.     END;
  302.     DelUnused
  303. END DeleteRedundantStates;
  304. PROCEDURE ConvertToStates*(gp0, sp: INTEGER);
  305. (*note: gn.line is abused as a state number!*)
  306.     VAR n: INTEGER; S: ARRAY maxStates OF State;
  307.     PROCEDURE TheState(gp: INTEGER): State;
  308.         VAR state: State; gn: CRT.GraphNode;
  309.     BEGIN
  310.         IF gp = 0 THEN state := NewState(); state.endOf := sp; RETURN state
  311.         ELSE CRT.GetNode(gp, gn); RETURN S[gn.line]
  312.         END 
  313.     END TheState;
  314.     PROCEDURE Step(from: State; gp: INTEGER);
  315.         VAR gn: CRT.GraphNode;
  316.     BEGIN
  317.         IF gp = 0 THEN RETURN END;
  318.         CRT.GetNode(gp, gn);
  319.         CASE gn.typ OF
  320.             CRT.class, CRT.char: NewTransition(from, TheState(ABS(gn.next)), gn.typ, gn.p1, gn.p2)
  321.         | CRT.alt: Step(from, gn.p1); Step(from, gn.p2)
  322.         | CRT.opt, CRT.iter: Step(from, ABS(gn.next)); Step(from, gn.p1)
  323.         END
  324.     END Step;
  325.     PROCEDURE FindTrans(gp: INTEGER; state: State);
  326.         VAR gn: CRT.GraphNode; new: BOOLEAN;
  327.     BEGIN
  328.         IF gp = 0 THEN RETURN END;  (*end of graph*)
  329.         CRT.GetNode(gp, gn); 
  330.         IF gn.line # 0 THEN RETURN END;  (*already visited*)
  331.         new := state = NIL;
  332.         IF new THEN state := NewState() END;
  333.         INC(n); S[n] := state; gn.line := n; CRT.PutNode(gp, gn);
  334.         IF CRT.DelGraph(gp) THEN state.endOf := sp END; (*state is end state*)
  335.         CASE gn.typ OF
  336.             CRT.class, CRT.char: FindTrans(ABS(gn.next), NIL);
  337.         | CRT.opt:  FindTrans(ABS(gn.next), NIL); FindTrans(gn.p1, state)
  338.         | CRT.iter: FindTrans(ABS(gn.next), state); FindTrans(gn.p1, state)
  339.         | CRT.alt:  FindTrans(gn.p1, state); FindTrans(gn.p2, state)
  340.         END;
  341.         IF new OR (state = firstState) & (gp = gp0) THEN (*start of a group of equally numbered nodes*)
  342.             Step(state, gp)
  343.         END
  344.     END FindTrans;
  345. BEGIN
  346.     IF CRT.DelGraph(gp0) THEN SemErr(20) END;
  347.     n := 0; FindTrans(gp0, firstState)
  348. END ConvertToStates;
  349. PROCEDURE MatchDFA* (s: ARRAY OF CHAR; sp: INTEGER; VAR matchedSp: INTEGER);
  350.     VAR state, to: State; a: Action; i, len: INTEGER;
  351. BEGIN (*s with quotes*)
  352.     state := firstState; i := 1; len := Length(s) - 1;
  353.     LOOP (*try to match s against existing DFA*)
  354.         IF i = len THEN EXIT END;
  355.         a := TheAction(state, s[i]);
  356.         IF a = NIL THEN EXIT END;
  357.         state := a.target.state; INC(i)
  358.     END;
  359.     WHILE i < len DO (*make new DFA for s[i..len-1]*)
  360.         to := NewState();
  361.         NewTransition(state, to, CRT.char, ORD(s[i]), CRT.normTrans);
  362.         state := to; INC(i)
  363.     END;
  364.     matchedSp := state.endOf;
  365.     IF state.endOf = CRT.noSym THEN state.endOf := sp END
  366. END MatchDFA;
  367. PROCEDURE SplitActions(a, b: Action);
  368. VAR c: Action; seta, setb, setc: CRT.Set;
  369.     PROCEDURE CombineTransCodes(t1, t2: INTEGER; VAR result:INTEGER);
  370.     BEGIN
  371.         IF t1 = CRT.contextTrans THEN result := t1 ELSE result := t2 END
  372.     END CombineTransCodes;
  373. BEGIN
  374.     MakeSet(a, seta); MakeSet(b, setb);
  375.     IF Sets.Equal(seta, setb) THEN
  376.         AddTargetList(b^.target, a^.target);
  377.         CombineTransCodes(a^.tc, b^.tc, a^.tc);
  378.         DetachAction(b, a)
  379.     ELSIF Sets.Includes(seta, setb) THEN
  380.         setc := seta; Sets.Differ(setc, setb);
  381.         AddTargetList(a^.target, b^.target);
  382.         CombineTransCodes(a^.tc, b^.tc, b^.tc);
  383.         ChangeAction(a, setc)
  384.     ELSIF Sets.Includes(setb, seta) THEN
  385.         setc := setb; Sets.Differ(setc, seta);
  386.         AddTargetList(b^.target, a^.target);
  387.         CombineTransCodes(a^.tc, b^.tc, a^.tc);
  388.         ChangeAction(b, setc)
  389.     ELSE
  390.         Sets.Intersect(seta, setb, setc);
  391.         Sets.Differ(seta, setc);
  392.         Sets.Differ(setb, setc);
  393.         ChangeAction(a, seta);
  394.         ChangeAction(b, setb);
  395.         NEW(c); c^.target:=NIL;
  396.         CombineTransCodes(a^.tc, b^.tc, c^.tc);
  397.         AddTargetList(a^.target, c^.target);
  398.         AddTargetList(b^.target, c^.target);
  399.         ChangeAction(c, setc);
  400.         AddAction(c, a)
  401. END SplitActions;
  402. PROCEDURE MakeUnique(state: State; VAR changed:BOOLEAN);
  403. VAR a, b: Action; 
  404.     PROCEDURE Overlap(a, b: Action): BOOLEAN;
  405.         VAR seta, setb: CRT.Set;
  406.     BEGIN
  407.         IF a^.typ = CRT.char THEN
  408.             IF b^.typ = CRT.char THEN RETURN a^.sym = b^.sym
  409.             ELSE CRT.GetClass(b^.sym, setb); RETURN Sets.In(setb, a^.sym)
  410.             END
  411.         ELSE
  412.             CRT.GetClass(a^.sym, seta);
  413.             IF b^.typ = CRT.char THEN RETURN Sets.In(seta, b^.sym)
  414.             ELSE CRT.GetClass(b^.sym, setb); RETURN ~ Sets.Different(seta, setb)
  415.             END
  416.         END
  417.     END Overlap;
  418. BEGIN
  419.     a := state.firstAction; changed := FALSE;
  420.     WHILE a # NIL DO
  421.         b := a^.next;
  422.         WHILE b # NIL DO
  423.             IF Overlap(a, b) THEN SplitActions(a, b); changed:=TRUE END;
  424.             b := b^.next;
  425.         END;
  426.         a:=a^.next
  427. END MakeUnique;
  428. PROCEDURE MeltStates(state: State; VAR correct:BOOLEAN);
  429.     action:  Action;
  430.     ctx:     BOOLEAN;
  431.     endOf:   INTEGER;
  432.     melt:    Melted;
  433.     set:     CRT.Set;
  434.     s:      State;
  435.     changed: BOOLEAN;
  436.     PROCEDURE AddMeltedSet(nr: INTEGER; VAR set: CRT.Set);
  437.     VAR m: Melted;
  438.     BEGIN
  439.         m := firstMelted;
  440.         WHILE (m # NIL) & (m^.state.nr # nr) DO m := m^.next END;
  441.         IF m = NIL THEN HALT(98) END;
  442.         Sets.Unite(set, m^.set);
  443.     END AddMeltedSet;
  444.     PROCEDURE GetStateSet(t: Target; VAR set: CRT.Set; VAR endOf: INTEGER; VAR ctx:BOOLEAN);
  445.     VAR statenr: INTEGER; (*lastS: State;*)
  446.     BEGIN
  447.         Sets.Clear(set); endOf := CRT.noSym; ctx := FALSE; (*lastS := NIL;*)
  448.         WHILE t # NIL DO
  449.             statenr := t.state.nr;
  450.             IF statenr <= lastSimState THEN Sets.Incl(set, statenr)
  451.             ELSE AddMeltedSet(statenr, set)
  452.             END;
  453.             IF t^.state^.endOf # CRT.noSym THEN
  454.                 IF (endOf = CRT.noSym) OR (endOf = t^.state^.endOf)
  455.                 (*OR (lastS^.firstAction # NIL) & (t^.state^.firstAction = NIL)*) THEN
  456.                     endOf := t^.state.endOf; (*lastS := t^.state*)
  457.                 ELSE
  458.                     PutS("$Tokens "); PutI(endOf); PutS(" and "); PutI(t^.state.endOf);
  459.                     PutS(" cannot be distinguished.$");
  460.                     correct:=FALSE
  461.                 END
  462.             END;
  463.             IF t^.state.ctx THEN ctx := TRUE;
  464.                 IF t.state.endOf # CRT.noSym THEN
  465.                     PutS("$Ambiguous CONTEXT clause.$"); correct := FALSE
  466.                 END
  467.             END;
  468.             t := t^.next
  469.         END
  470.     END GetStateSet;
  471.     PROCEDURE FillWithActions(state: State; targ: Target);
  472.     VAR action,a: Action;
  473.     BEGIN
  474.         WHILE targ # NIL DO
  475.             action := targ^.state.firstAction;
  476.             WHILE action # NIL DO
  477.                 NEW(a); a^ := action^; a^.target := NIL; 
  478.                 AddTargetList(action^.target, a^.target);
  479.                 AddAction(a, state.firstAction);
  480.                 action:=action^.next
  481.             END;
  482.             targ:=targ^.next
  483.         END;
  484.     END FillWithActions;
  485.     PROCEDURE KnownMelted(set:CRT.Set; VAR melt: Melted): BOOLEAN;
  486.     BEGIN
  487.         melt := firstMelted;
  488.         WHILE melt # NIL DO
  489.             IF Sets.Equal(set, melt^.set) THEN RETURN TRUE END;
  490.             melt := melt^.next
  491.         END;
  492.         RETURN FALSE
  493.     END KnownMelted;
  494. BEGIN
  495.     action := state.firstAction;
  496.     WHILE action # NIL DO
  497.         IF action^.target^.next # NIL THEN (*more than one target state*)
  498.             GetStateSet(action^.target, set, endOf, ctx);
  499.             IF ~ KnownMelted(set, melt) THEN
  500.                 s := NewState(); s.endOf := endOf; s.ctx := ctx;
  501.                 FillWithActions(s, action^.target);
  502.                 REPEAT MakeUnique(s, changed) UNTIL ~ changed;
  503.                 melt := NewMelted(set, s);
  504.             END;
  505.             action^.target^.next:=NIL;
  506.             action^.target^.state := melt^.state
  507.         END;
  508.         action := action^.next
  509.     END;
  510.     Texts.Append(Oberon.Log, out.buf)
  511. END MeltStates;
  512. PROCEDURE MakeDeterministic*(VAR correct: BOOLEAN);
  513.     VAR state: State; changed: BOOLEAN;
  514.     PROCEDURE FindCtxStates; (*find states reached by a context transition*)
  515.     VAR a: Action; state: State;
  516.     BEGIN
  517.         state := firstState;
  518.         WHILE state # NIL DO
  519.             a := state.firstAction;
  520.             WHILE a # NIL DO
  521.                 IF a^.tc = CRT.contextTrans THEN a^.target^.state.ctx := TRUE END;
  522.                 a := a^.next
  523.             END;
  524.             state := state.next
  525.         END;
  526.     END FindCtxStates;
  527. BEGIN
  528.     IF lastState = NIL THEN lastSimState := 0 ELSE lastSimState := lastState.nr END;
  529.     FindCtxStates;
  530.     state := firstState;
  531.     WHILE state # NIL DO
  532.         REPEAT MakeUnique(state, changed) UNTIL ~ changed;
  533.         state := state.next 
  534.     END;
  535.     correct := TRUE;
  536.     state := firstState;
  537.     WHILE state # NIL DO MeltStates(state, correct); state := state.next END;
  538.     DeleteRedundantStates;
  539.     CombineShifts
  540. END MakeDeterministic;
  541. PROCEDURE PrintSymbol(typ, val, width: INTEGER);
  542. VAR name: CRT.Name; len: INTEGER;
  543. BEGIN
  544.     IF typ = CRT.class THEN
  545.         CRT.GetClassName(val, name); PutS(name); len := Length(name)
  546.     ELSIF (val >= ORD(" ")) & (val < 127) & (val # 34) THEN
  547.         Put(CHR(34)); Put(CHR(val)); Put(CHR(34)); len:=3
  548.     ELSE
  549.         PutS("CHR("); PutI2(val, 2); Put(")"); len:=7
  550.     END;
  551.     WHILE len < width DO Put(" "); INC(len) END
  552. END PrintSymbol;
  553. PROCEDURE PrintStates*;
  554. VAR action: Action; first: BOOLEAN; state: State; i: INTEGER; targ: Target; set: CRT.Set; name: CRT.Name;
  555. BEGIN
  556.     PutS("$-------- states ---------$");
  557.     state := firstState;
  558.     WHILE state # NIL DO
  559.         action := state.firstAction; first:=TRUE;
  560.         IF state.endOf = CRT.noSym THEN PutS("     ") 
  561.         ELSE PutS("E("); PutI2(state.endOf, 2); Put(")")
  562.         END;
  563.         PutI2(state.nr, 3); Put(":"); IF action = NIL THEN PutS(" $") END;
  564.         WHILE action # NIL DO
  565.             IF first THEN Put(" "); first:=FALSE ELSE PutS("          ") END;
  566.             PrintSymbol(action^.typ, action^.sym, 0); Put(" ");
  567.             targ := action^.target;
  568.             WHILE targ # NIL DO
  569.                 PutI(targ^.state.nr); Put(" "); targ := targ^.next;
  570.             END;
  571.             IF action^.tc = CRT.contextTrans THEN PutS(" context$") ELSE PutS(" $") END;
  572.             action := action^.next
  573.         END;
  574.         state := state.next
  575.     END;
  576.     PutS("$-------- character classes ---------$");
  577.     i := 0;
  578.     WHILE i <= CRT.maxC DO
  579.         CRT.GetClass(i, set); CRT.GetClassName(i, name); PutS(name); PutS(": ");
  580.         Sets.Print(out, set, 80, 13); Texts.WriteLn(out);
  581.         INC(i)
  582.     END;
  583.     Texts.Append(Oberon.Log, out.buf)
  584. END PrintStates;
  585. PROCEDURE GenComment(com:Comment);
  586.     PROCEDURE GenBody;
  587.     BEGIN
  588.         PutS("      LOOP$");
  589.         PutS("        IF "); PutChCond(com^.stop[0]); PutS(" THEN$");
  590.         IF Length(com^.stop) = 1 THEN
  591.             PutS("          DEC(level); oldEols := chLine - startLine; NextCh;$");
  592.             PutS("          IF level = 0 THEN RETURN TRUE END;$");
  593.         ELSE
  594.             PutS("          NextCh;$");
  595.             PutS("          IF "); PutChCond(com^.stop[1]); PutS(" THEN$");
  596.             PutS("            DEC(level); oldEols := chLine - startLine; NextCh;$");
  597.             PutS("            IF level=0 THEN RETURN TRUE END$");
  598.             PutS("          END;$");
  599.         END;
  600.         IF com^.nested THEN
  601.             PutS("        ELSIF "); PutChCond(com^.start[0]); PutS(" THEN$");
  602.             IF Length(com^.start) = 1 THEN
  603.                 PutS("          INC(level); NextCh;$");
  604.             ELSE
  605.                 PutS("          NextCh;$");
  606.                 PutS("          IF "); PutChCond(com^.start[1]); PutS(" THEN$");
  607.                 PutS("            INC(level); NextCh;$");
  608.                 PutS("          END;$");
  609.             END;
  610.             END;
  611.         PutS("        ELSIF ch = EOF THEN RETURN FALSE$");
  612.         PutS("        ELSE NextCh END;$");
  613.         PutS("      END;$");
  614.         END GenBody;
  615. BEGIN
  616.     PutS("  IF "); PutChCond(com^.start[0]); PutS(" THEN$");
  617.     IF Length(com^.start) = 1 THEN
  618.         PutS("    NextCh;$");
  619.         GenBody;
  620.         PutS("  END;");
  621.     ELSE
  622.         PutS("    NextCh;$");
  623.         PutS("    IF "); PutChCond(com^.start[1]); PutS(" THEN$");
  624.         PutS("      NextCh;$");
  625.         GenBody;
  626.         PutS("    ELSE$");
  627.         PutS("      IF ch = EOL THEN DEC(chLine); lineStart := oldLineStart END;$");
  628.         PutS("      DEC(chPos, 2); Texts.OpenReader(r, src, chPos+1); NextCh; RETURN FALSE$");
  629.         PutS("    END$");
  630.         PutS("  END;");
  631.     END;
  632.     END GenComment;
  633. PROCEDURE CopyFramePart (stopStr: ARRAY OF CHAR); (*Copy from file <fram> to file <out> until <stopStr>*)
  634.     VAR ch, startCh: CHAR; i, j, high: INTEGER;
  635. BEGIN
  636.     startCh := stopStr[0]; high := Length(stopStr) - 1; Texts.Read (fram, ch);
  637.     WHILE ch # 0X DO
  638.         IF ch = startCh THEN (* check if stopString occurs *)
  639.             i := 0;
  640.             REPEAT
  641.                 IF i = high THEN RETURN END;  (*stopStr[0..i] found; no unrecognized character*)
  642.                 Texts.Read (fram, ch); INC(i);
  643.             UNTIL ch # stopStr[i];
  644.             (*stopStr[0..i-1] found; 1 unrecognized character*)
  645.             j := 0; WHILE j < i DO Texts.Write(out, stopStr[j]); INC(j) END
  646.         ELSE Texts.Write (out, ch); Texts.Read(fram, ch)
  647.         END
  648. END CopyFramePart;
  649. PROCEDURE GenLiterals;
  650.     VAR 
  651.         i, j, k, l: INTEGER; 
  652.         key: ARRAY 128 OF CRT.Name; 
  653.         knr: ARRAY 128 OF INTEGER;
  654.         ch: CHAR;
  655.         sn: CRT.SymbolNode;
  656. BEGIN
  657.     (*-- sort literal list*)
  658.     i := 0; k := 0;
  659.     WHILE i <= CRT.maxT DO
  660.         CRT.GetSym(i, sn);
  661.         IF sn.struct = CRT.litToken THEN
  662.             j := k-1; WHILE (j >= 0) & (sn.name < key[j]) DO key[j+1] := key[j]; knr[j+1] := knr[j]; DEC(j) END;
  663.             key[j+1] := sn.name; knr[j+1] := i; INC(k)
  664.         END;
  665.         INC(i)
  666.     END;
  667.     (*-- print case statement*)
  668.     IF k > 0 THEN
  669.         PutS("    IF (lexeme[0] >= "); PutC(key[0, 1]); PutS(") & (lexeme[0] <= "); PutC(key[k-1, 1]); PutS(") THEN$");
  670.         PutS("      CASE lexeme[0] OF$");
  671.         i := 0;
  672.         WHILE i < k DO
  673.             ch := key[i, 1];  (*key[i, 0] = quote*)
  674.             PutS("      | "); PutC(ch); j := i;
  675.             REPEAT
  676.                 IF i = j THEN PutS(": IF lexeme = ") ELSE PutS("        ELSIF lexeme = ") END;
  677.                 PutS(key[i]); PutS(" THEN sym := "); PutI(knr[i]); Put(CHR(13));
  678.                 INC(i)
  679.             UNTIL (i = k) OR (key[i, 1] # ch);
  680.             PutS("        END$");
  681.         END;
  682.         PutS("      ELSE$      END$    END;$")
  683. END GenLiterals;
  684. PROCEDURE WriteState(state: State);
  685.     VAR action: Action; first, ctxEnd: BOOLEAN; sn: CRT.SymbolNode; endOf: INTEGER;
  686.         set: CRT.Set;
  687. BEGIN
  688.     endOf := state.endOf;
  689.     IF (endOf > CRT.maxT) & (endOf # CRT.noSym) THEN (*pragmas have been moved*)
  690.         endOf := CRT.maxT + CRT.maxSymbols - endOf 
  691.     END;
  692.     PutS("    | "); PutI2(state.nr, 2); PutS(": ");
  693.     first:=TRUE; ctxEnd := state.ctx;
  694.     action := state.firstAction;
  695.     WHILE action # NIL DO
  696.         IF first THEN PutS("IF "); first:=FALSE ELSE PutS("          ELSIF ") END;
  697.         IF action^.typ = CRT.char THEN PutChCond(CHR(action^.sym))
  698.         ELSE CRT.GetClass(action^.sym, set); PutRange(set)
  699.         END;
  700.         PutS(" THEN");
  701.         IF action.target.state.nr # state.nr THEN
  702.             PutS(" state := "); PutI(action.target.state.nr); Put(";")
  703.         END;
  704.         IF action^.tc = CRT.contextTrans THEN PutS(" INC(apx)"); ctxEnd := FALSE 
  705.         ELSIF state.ctx THEN PutS(" apx := 0") 
  706.         END;
  707.         PutS(" $");
  708.         action := action^.next
  709.     END;
  710.     IF state.firstAction # NIL THEN PutS("          ELSE ") END;
  711.     IF endOf = CRT.noSym THEN PutS("sym := noSym; ")
  712.     ELSE (*final state*)
  713.         CRT.GetSym(endOf, sn);
  714.         IF ctxEnd THEN (*final context state: cut appendix*)
  715.             PutS("chPos := chPos - apx - 1; Texts.OpenReader(r, src, chPos+1); NextCh; ")
  716.         END;
  717.         PutS("sym := "); PutI(endOf); PutS("; ");
  718.         IF sn.struct = CRT.classLitToken THEN PutS("CheckLiteral; ") END
  719.     END;
  720.     PutS("RETURN$");
  721.     IF state.firstAction # NIL THEN PutS("          END;$") END
  722. END WriteState;
  723. PROCEDURE *Show (t: Texts.Text; op: INTEGER; beg, end: LONGINT);
  724. END Show;
  725. PROCEDURE WriteScanner*;
  726.     scanner: ARRAY 32 OF CHAR;
  727.     name:     ARRAY 64 OF CHAR;
  728.     startTab: ARRAY 128 OF INTEGER;
  729.     com:      Comment;
  730.     i, j, l:  INTEGER;
  731.     gn:       CRT.GraphNode;
  732.     sn:       CRT.SymbolNode;
  733.     state: State;
  734.     t: Texts.Text;
  735.     PROCEDURE FillStartTab;
  736.         VAR action: Action; i, targetState: INTEGER; class: CRT.Set;
  737.     BEGIN
  738.         startTab[0] := stateNr + 1; (*eof*)
  739.         i := 1; WHILE i < 128 DO startTab[i] := 0; INC(i) END;
  740.         action := firstState.firstAction;
  741.         WHILE action # NIL DO
  742.             targetState := action.target.state.nr;
  743.             IF action^.typ = CRT.char THEN 
  744.                 startTab[action^.sym] := targetState
  745.             ELSE
  746.                 CRT.GetClass(action^.sym, class); i := 0;
  747.                 WHILE i < 128 DO
  748.                     IF Sets.In(class, i) THEN startTab[i] := targetState END;
  749.                     INC(i)
  750.                 END
  751.             END;
  752.             action := action^.next
  753.         END
  754.     END FillStartTab;
  755. BEGIN
  756.     FillStartTab;
  757.     CRT.GetNode(CRT.root, gn); CRT.GetSym(gn.p1, sn);
  758.     COPY(sn.name, scanner); l := Length(scanner); scanner[l] := "S"; scanner[l+1] := 0X;
  759.     NEW(t); Texts.Open(t, "Scanner.FRM"); Texts.OpenReader(fram, t, 0);
  760.     IF t.len = 0 THEN
  761.         Texts.WriteString(out, "Scanner.FRM not found"); Texts.WriteLn(out);
  762.         Texts.Append(Oberon.Log, out.buf); HALT(99)
  763.     END;
  764.     Texts.Append(Oberon.Log, out.buf);
  765.     (*------- *S.MOD -------*)
  766.     CopyFramePart("-->modulename"); PutS(scanner);
  767.     CopyFramePart("-->declarations"); PutS("  noSym = "); PutI(CRT.maxT); Put(";");
  768.     CopyFramePart("-->comment");
  769.     com := firstComment;
  770.     WHILE com # NIL DO GenComment(com); com := com^.next END;
  771.     CopyFramePart("-->literals"); GenLiterals;
  772.     CopyFramePart("-->GetSy1");
  773.     IF ~ Sets.In(CRT.ignored, ORD(EOL)) THEN PutS("  IF oldEols > 0 THEN DEC(oldEols); ch := EOL END;$") END;
  774.     PutS("  WHILE (ch=20X)"); IF ~ Sets.Empty(CRT.ignored) THEN PutS(" OR ") END;
  775.     PutRange(CRT.ignored); PutS(" DO NextCh END;");
  776.     IF firstComment # NIL THEN
  777.         PutS("$    IF ("); com := firstComment;
  778.         WHILE com # NIL DO
  779.             PutChCond(com^.start[0]);
  780.             IF com^.next # NIL THEN PutS(" OR ") END;
  781.             com := com^.next
  782.         END;
  783.         PutS(") & Comment() THEN Get(sym); RETURN END;")
  784.     END;
  785.     CopyFramePart("-->GetSy2");
  786.     state := firstState.next;
  787.     WHILE state # NIL DO WriteState(state); state := state.next END;
  788.     PutS("    | "); PutI2(stateNr + 1, 2); PutS(": sym := 0; ch := 0X; RETURN$");
  789.     CopyFramePart("-->initialization");
  790.     i := 0;
  791.     WHILE i < 32 DO
  792.         j := 0; PutS("  ");
  793.         WHILE j < 4 DO
  794.             PutS("start["); PutI(4*i+j); PutS("]:="); PutI(startTab[4*i+j]); PutS("; ");
  795.             INC(j)
  796.         END;
  797.         Texts.WriteLn(out); 
  798.         INC(i)
  799.     END;
  800.     CopyFramePart("-->modulename"); PutS(scanner); Put(".");
  801.     NEW(t); t.notify := Show; Texts.Open(t, ""); Texts.Append(t, out.buf);
  802.     l := Length(scanner); scanner[l] := "."; scanner[l+1] := "M"; scanner[l+2] := "o"; scanner[l+3] := "d"; scanner[l+4] := 0X;
  803.     Texts.Close(t, scanner)
  804. END WriteScanner;
  805. PROCEDURE Init*;
  806. BEGIN
  807.     firstState := NIL; lastState := NIL; stateNr := -1;
  808.     rootState := NewState();
  809.     firstMelted := NIL; firstComment := NIL
  810. END Init;
  811. BEGIN
  812.     Texts.OpenWriter(out)
  813. END CRA.
  814.